package demo.selenium;

import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/11/22 下午3:36
 * @UpdateDate:
 * @Description: 该脚本意在爬取 365rili.com 万年历信息, 组织SQL，进行入库.
 */
public class CalendarFetch {

    static final String HOST = "http://www.365rili.com/main/calendar.do";
    static final String SQL_FILE = "/Users/icasue/Desktop/业务智能/d_date_2022_2025.sql";

    public static void main(String[] args) {
        // 浏览器驱动.
        System.setProperty("webdriver.chrome.driver", "/Users/icasue/Desktop/lbs-server-plugins/icasue-plugins-demos/icasue-demo-selenium/src/main/resources/drivers/chromedriver_98");
        // 创建浏览器驱动
        ChromeDriver driver = null;
        try {
            driver = new ChromeDriver();
            // 访问HOST.
            driver.navigate().to(HOST);

            // 创建cookie.
            long timeout = System.currentTimeMillis() + (1 * 24 * 60 * 60 * 1000);
            Date expire = new Date(timeout);
            Cookie cookie = new Cookie("auto", "313307527%252d5530235abb2e2a395f0a9bd25fb88f", "/", expire);
            driver.manage().addCookie(cookie);

            // 刷新页面.
            driver.navigate().to(HOST);

            // 切换到周历.
            WebElement ul_view_switcher = driver.findElement(By.id("ul_view_switcher"));
            List<WebElement> li = ul_view_switcher.findElements(By.xpath("li"));
            WebElement week_layout = li.get(2);
            week_layout.click();

            // 创建行为代理.
            ActionProxy actionProxy = new ActionProxy();

            // 获取当前年月周.
            WebElement sp_week = driver.findElement(By.id("sp_week"));
            actionProxy.sp_week = sp_week;

            // 获取下一页点击链接,
            WebElement lnk_next = driver.findElement(By.id("lnk_next"));
            actionProxy.lnk_next = lnk_next;

            // 获取周视图.
            WebElement div_wview = driver.findElement(By.id("div_wview"));
            actionProxy.weekView = div_wview;

            // 从周视图获取周的天数序列.
            actionProxy.weekDaySeq = div_wview.findElements(By.xpath("tbody/tr[1]/td/dl/dt"));

            // 获取dateBo
            actionProxy.weekDaySeq.get(0).click();
            WebElement date_box = driver.findElement(By.id("div_add_schedule"))
                    .findElement(By.xpath("div[1]/form[1]/div[2]/dl[2]/dd[1]/ul[1]/li[1]/input[1]"));
            actionProxy.dateBox = date_box;

            // 获取dateBox关闭连接.
            WebElement link_close_date_box = driver.findElement(By.id("div_add_schedule")).findElement(By.xpath("a[1]"));
            actionProxy.linkCloseDateBox = link_close_date_box;
            link_close_date_box.click();

            // 创建文件Write流.
            final BufferedWriter writer = new BufferedWriter(new FileWriter(SQL_FILE,false));
            actionProxy.writer = writer;

            Integer year = null;
            while (year == null || year <= 2025){
                actionProxy.tryNextPage();
                year = actionProxy.parse();
            }

            // 销毁.
            actionProxy.destroy();
        }catch (Throwable e){
            e.printStackTrace();
        }finally {
            // 退出浏览器驱动，释放资源.
            if(driver != null){
                driver.quit();
            }
        }

    }

    static class ActionProxy {
        public BufferedWriter writer;
        // 获取当前年月周原始文本.
        public WebElement sp_week;
        //下一页点击链接.
        public WebElement lnk_next;
        // 周视图.
        private WebElement weekView;
        // td/dl/dt元素序列(7列，周一至周日)
        public List<WebElement> weekDaySeq;

        public WebElement dateBox;
        public WebElement linkCloseDateBox;


        public void tryNextPage(){
            lnk_next.click();
        }

        public Integer parse(){
            String year_week_month_enhancer = sp_week.getText();
            String[] year_black_week_month = year_week_month_enhancer
                    .replaceAll(" ", "")
                    .replaceAll("\\D", "-")
                    .split("-");
            Integer[] year_week_month = Arrays.asList(year_black_week_month).stream().filter(item -> !item.equals(""))
                    .map(item -> Integer.parseInt(item)).toArray(Integer[]::new);


            if(weekDaySeq == null){
                System.out.println("年: " + year_black_week_month[0]);
                System.out.println("月: " + year_black_week_month[3]);
                System.out.println("周: " + year_black_week_month[2]);
            }else {
                for (int i = 1; i <= weekDaySeq.size(); i++) {
                    WebElement currentDay = weekDaySeq.get(i - 1);
                    currentDay.click();

                    String[] yyyy_MM_dd = null;
                    do {
                        yyyy_MM_dd = dateBox.getAttribute("value").split("-");
                    }while(yyyy_MM_dd.length != 3);

                    try {
                        linkCloseDateBox.click();
                    }catch (Throwable e){
                        e.printStackTrace();
                    }

                    List<WebElement> elements = currentDay.findElements(By.xpath("*"));
                    String holidayName = elements.get(0).getText();
                    String dayOfMonth = elements.get(1).getText();

                    year_week_month[0] = Integer.parseInt(yyyy_MM_dd[0]);
                    year_week_month[2] = Integer.parseInt(yyyy_MM_dd[1]);

                    String specialDay = null;
                    if(elements.size() > 2){
                        specialDay = elements.get(2).getText();
                    }
                    DDate dDate = new DDate(
                            year_week_month[0],
                            year_week_month[2],
                            year_week_month[1],
                            i,
                            dayOfMonth
                    );

                    dDate.holiday_name = holidayName;

                    if(specialDay != null){
                        if(specialDay.equals("放假")){
                            dDate.holiday_type = 3;
                            dDate.is_holiday = 1;
                            dDate.is_workday = 0;
                            dDate.is_weekend = 1;
                        }else if(specialDay.equals("工作")){
                            dDate.holiday_type = 1;
                            dDate.is_workday = 1;
                            dDate.is_weekend = 0;
                        }else {

                        }
                    }
                    String sql = dDate.toSQL();
                    try {
                        writer.write(sql);
                        writer.flush();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    System.out.println(sql);
                }
            }
            return Integer.parseInt(year_black_week_month[0]);
        }

        public void destroy(){
            this.sp_week = null;
            this.lnk_next = null;
            this.weekView = null;
            this.weekDaySeq = null;
            this.dateBox = null;
            this.linkCloseDateBox = null;
            if(this.writer != null){
                try {
                    this.writer.flush();
                    this.writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }


    public static class DDate{
        static final String SQL_TEMPLATE = "INSERT INTO `lbs_map_bi_service`.`d_date` (\n"
                 + "\t`calendar_dt`, `calendar_year`, `quarter_of_year`, `month_of_year`, \n"
                 + "\t`week_of_year`, `day_of_week`, `day_of_month`, `day_of_year`, \n"
                 + "\t`is_workday`, `is_weekend`, `is_holiday`, `holiday_name`, `holiday_type`, \n"
                 + "\t`update_time`, `create_time` \n"
                 + ") VALUES (\n\t'%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%s,%s\n);\n";
        static final Map<Integer, AtomicInteger> $$ = new HashMap<>();
        public String calendar_dt;
        public Integer calendar_year;
        public Integer quarter_of_year;
        public Integer month_of_year;
        public Integer week_of_year;
        public Integer day_of_week;
        public Integer day_of_month;
        public Integer day_of_year; //**
        public Integer is_workday = 1;  // dayofweek
        public Integer is_weekend = 0;  // dayofweek
        public Integer is_holiday = 0;
        public String holiday_name;

        public Integer holiday_type = 1; // '工作日：1，周末：2，节假日：3',

        public DDate(Integer calendar_year,
                     Integer month_of_year,
                     Integer week_of_year,
                     Integer day_of_week,
                     String day_of_month){
            this.calendar_year = calendar_year;
            this.month_of_year = month_of_year;
            this.week_of_year = week_of_year;
            this.day_of_week = day_of_week;
            this.day_of_month = Integer.parseInt(day_of_month);
            this.calendar_dt = String.format("%s-%02d-%02d", this.calendar_year, this.month_of_year, this.day_of_month);
            this.quarter_of_year = this.month_of_year % 3 == 0 ? this.month_of_year / 3 : (this.month_of_year / 3) + 1;

            AtomicInteger acculater = $$.get(this.calendar_year);
            if(acculater == null){
                acculater = new AtomicInteger(1);
                $$.put(this.calendar_year, acculater);
            }

            this.day_of_year = acculater.getAndIncrement();

            if(this.day_of_week > 5){
                this.holiday_type = 2;
                this.is_workday = 0;
                this.is_weekend = 1;
            }
        }

        public String toSQL(){
            String sql = String.format(SQL_TEMPLATE,
                    calendar_dt, calendar_year, quarter_of_year, month_of_year,
                    week_of_year, day_of_week, day_of_month, day_of_year,
                    is_workday, is_weekend, is_holiday, holiday_name, holiday_type,
                    "now()", "now()"
            );
            return sql;
        }
    }


}
